package smashedapples.core
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.utils.Dictionary;

	import mx.core.IMXMLObject;
	import mx.events.FlexEvent;
	import mx.managers.ISystemManager;

	[Event( name="creationComplete", type = "mx.events.FlexEvent" )]

	[Mixin]
	dynamic public class NonVisualComponent extends EventDispatcher implements IMXMLObject, IEventDispatcher
	{

		public static function init( systemManager:ISystemManager ):void
		{
			NonVisualComponent.systemManager = systemManager;
		}

		private static var systemManager:ISystemManager;

		public function initialized( document:Object, id:String ):void
		{

			this.document = document;
			this.id = id;

			this.dispatchEvent( new FlexEvent( FlexEvent.CREATION_COMPLETE, true, false ));
		}

		public function NonVisualComponent():void
		{
			super();
		}

		protected var changedProperties:Dictionary = new Dictionary();

		public function addPropertyChanged( property:String, invalidate:Boolean = true ):void
		{
			changedProperties[ property ] = true;
			if( invalidate )
				this.invalidateProperties();
		}

		public function hasPropertyChanged( property:String ):Boolean
		{
			if( this.changedProperties[ property ] == true )
				return true;
			return false;
		}

		public function removePropertyChanged( property:String ):void
		{
			this.changedProperties[ property ] = false;
		}

		public function invalidateProperties():void
		{
			this.callLater( commitProperties )
		}


		protected function commitProperties():void
		{
			for( var property:String in this.changedProperties )
			{
				var handlerName:String = getCommitPropertyHandlerName( property );

				if( this.hasOwnProperty( handlerName ))
				{
					var method:Function = this[ handlerName ] as Function;
					method.apply( this );
				}

				this.removePropertyChanged( property );
			}
		}

		public function getCommitPropertyHandlerName( property:String ):String
		{
			return "onCommit" + property.substr( 0, 1 ).toUpperCase() + property.slice( 1 );
		}

		public function callLater( method:Function ):void
		{
			this.queue[ method ] = method;
			this.addListeners();
		}

		public function validateNow():void
		{
			commitProperties();
		}


		private function addListeners():void
		{
			systemManager.stage.addEventListener( Event.ENTER_FRAME, callLaterDispatcher );
		}

		private function removeListeners():void
		{
			systemManager.stage.removeEventListener( Event.ENTER_FRAME, callLaterDispatcher );
		}

		private function callLaterDispatcher( event:Event ):void
		{
			for each( var method:Function in queue )
			{
				method();
			}
			queue = new Dictionary();
			removeListeners();
		}


		private var queue:Dictionary = new Dictionary();

		public var document:Object;

		public var id:String;


		public function setValue( name:String, value:* = null, defaultValue:* = null ):void
		{
			this[ name ] = ( value != null ) ? value : defaultValue;
		}

		public function setValueIfNotNull( name:String, value:* = null ):void
		{
			if( value != null )
				this[ name ] = value;
		}


	}
}